package com.lianqi.emcpframework.logging.level.strategy;

import java.io.InputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Stream;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import com.alibaba.fastjson.JSON;
import com.lianqi.emcpframework.logging.context.InvokingLoggerContext;

/**
 * @program emcp-framework
 * @ClassName LogLevelStrategy
 * @description: 日志级别策略
 * @author: sky
 * @create: 2019/05/10 14:19
 */
public interface LogLevelStrategy {

    Class[] EXCLUDES =
        {ServletRequest.class, ServletResponse.class, InputStream.class, OutputStream.class, MultipartFile.class};

    /**
     * 转换方法
     *
     * @param context
     *            方法调用日志上下文
     * @return map格式日志信息
     */
    Map<String, Object> parse(InvokingLoggerContext context);

    /**
     * 字段过滤器
     * 
     * @return
     */
    default Function<Object, Serializable> objectFilter() {
        return obj -> {
            if (Stream.of(EXCLUDES).anyMatch(aClass -> memberIsInstance(aClass, obj))) {
                return obj.getClass().getName();
            }
            return (Serializable)JSON.toJSON(obj);
        };
    }

    /**
     * 判断数据成员 是否为给定的类型实例
     * 
     * @param aClass
     * @param obj
     * @return
     */
    default boolean memberIsInstance(Class aClass, Object obj) {
        if (obj == null) {
            return false;
        }
        if (obj instanceof Collection) {
            Object element = ((Collection)obj).iterator().hasNext() ? ((Collection)obj).iterator().next() : null;
            return memberIsInstance(aClass, element);
        }
        if (obj.getClass().isArray()) {
            Object element = null;
            if (Array.getLength(obj) > 0) {
                element = Array.get(obj, 0);
            }
            return memberIsInstance(aClass, element);
        }
        if (obj instanceof Map) {
            Map map = (Map)obj;
            boolean flag = false;
            if (!CollectionUtils.isEmpty(map)) {
                for (Iterator ite = map.keySet().iterator(); ite.hasNext();) {
                    if (memberIsInstance(aClass, map.get(ite.next()))) {
                        flag = true;
                    }
                }
            }
            return flag;
        }
        return aClass.isInstance(obj);
    }

}
